//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D torus_texture : register( t0 );
SamplerState wrap_sampler : register( s0 );

cbuffer cb_transformations : register( b0 )
{
    matrix world;
    matrix view;
    matrix projection;
    matrix normal_matrix;
    float4 wave_offset;
};

cbuffer cb_lighting : register( b1 )
{
    float3 light_dir;
    float material_specular_power;
    float4 light_color;
    float4 ambient_material_color;
    float4 diffuse_material_color;
    float4 specular_material_color;    
};

//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float3 Pos : POSITION;
    float3 Norm : NORMAL;
    float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR0;
    float2 Tex : TEXCOORD;        
};


//--------------------------------------------------------------------------------------
// Helper Functions
//--------------------------------------------------------------------------------------
struct ColorOut
{
    float4 ambient;
    float4 diffuse;
    float4 specular;
};

ColorOut DirectionalLight(float3 normal, float3 view_dir)
{
    // math done in view coordinates
    float3 light_dir_vc = -normalize(mul((float3x3)view, light_dir)); // there is no scale in view matrix
    
    float3 double_normal = 2.0f * normal;
    float doublenDotL = dot(double_normal, light_dir_vc);
    float3 reflexion = doublenDotL * normal - light_dir_vc;
    float vDotR = max(0.0, dot(view_dir, reflexion));

    float nDotL = max(0.0, dot(normal, normalize(light_dir_vc)));
        
    ColorOut output;
    output.ambient = light_color;
    output.diffuse = light_color * nDotL;
    output.specular = light_color * pow(vDotR, material_specular_power);
    
    return output;
}


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

    float beta = input.Tex.x * 2.0f * 3.14159f;
    input.Pos = input.Pos + sin( 4.0f * (wave_offset.x + beta)) * input.Norm * 0.05f;

	float4 worldspace_position = mul( world, float4(input.Pos,1.0f) );
    float4 viewspace_position = mul( view, worldspace_position );
    output.Pos = mul( projection, viewspace_position );

    output.Tex = input.Tex;
        
    float3 viewspace_normal = normalize(mul((float3x3)normal_matrix, input.Norm));
    
    float4 viewspace_view_dir = -normalize(viewspace_position);

    ColorOut directional_color = DirectionalLight(viewspace_normal, viewspace_view_dir);
    output.Color = saturate(ambient_material_color * directional_color.ambient + diffuse_material_color * directional_color.diffuse + specular_material_color * directional_color.specular);
           
    return output;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
    float alpha = input.Tex.y * 2.0f * 3.14159f;
    input.Tex.x = input.Tex.x + sin( 2.0f*(alpha + wave_offset.x) );
    return torus_texture.Sample( wrap_sampler, input.Tex * 8.0f) * input.Color;
}
